import common
import Queue,threading,random,requests,socket,httplib,urllib,thread,time
#google.com
#google.com.hk
#google.cn
#ipv6.google.com

globalVars = common.getGlobalVars()
lastTimeTestedInternetConnection = None


class ConnectManager(threading.Thread):
    sessions = []
    abandonSessionQueue = None
    shutDownFlag = None
    isStartUp = None
    availiableProxies = None
    googleFrontServerIp = None
    googleFrontServerStatus = None
    
    def __init__(self):
        threading.Thread.__init__(self)
        self.isStartUp = True
        self.availiableProxies = Queue.Queue()
        self.abandonSessionQueue = Queue.Queue()
        self.shutDownFlag = False
        self.callback = None
        self._makeGoogleFrontServerList()


    def _threadInit(self):
        #find 5 just use first 5
        self._simpleTestConnection(self.googleFrontServerIp[0:10])

    def _makeGoogleFrontServerList(self):
        self.googleFrontServerIp = []
        for address in globalVars.IPV4_GOOGLE :
            self.googleFrontServerIp.append(GFSIP(address))
        if globalVars.IPV6_ENABLE:
            for address in globalVars.IPV6_GOOGLE :
                self.googleFrontServerIp.append(GFSIP(address))
        #randomlize
        random.shuffle(self.googleFrontServerIp)

    def checkAbandonSesson(self):
        common.logger(3,"ConnectManager.run","Daemon Thread Working")
        try:
            abandonSession = self.abandonSessionQueue.get(block = True,
                                                          timeout = 1)
            abandonSession.close()
            common.logger(3,"ConnectManager.abandonSesson",\
                                  "Abandon Session")
            self._testOneProxy()
        except Queue.Empty:
            pass
            
    def checkAvailiableProxies(self):
        try:
            while(True):
                result,proxy = self.availiableProxies.get(block = True,
                                                          timeout = 1)
                if result == True and self.callback != None:
                    common.logger(3,"ConnectManager.addSession",\
                                  "Adding Session")
                    session = self._setProxySession(proxy.getAddress())
                    self.callback(session)
                
        except Queue.Empty:
            pass

    def checkLog(self):
        common.printLog()
        
    def run(self):
        if self.isStartUp :
            self.isStartUp = False
            self._threadInit()
            
        while(not self.shutDownFlag):
            self.checkAbandonSesson()
            self.checkAvailiableProxies()
            self.checkLog()       
            
            
            
        self._closeSessions()
        
    def getSession(self,count = 1,block = False,timeout = None,callback = None):
        #every new sessions makes a callback
        # to do make this stronger
        sessions = []
        self.callback = callback
        for _ in range(count):
            try:
                result,proxy = self.availiableProxies.get(block,timeout)
                if result == True:
                    session = self._setProxySession(proxy.getAddress())
                    sessions.append(session)
                    self.sessions.append(session)
                else: #get one tested
                    self._testOneProxy()
                proxy.setUsing()
            except Queue.Empty:
                pass              
        return sessions

    def _testOneProxy(self):
        for proxy in self.googleFrontServerIp:
            if not proxy.isTested():
                self._simpleTestConnection([proxy,])
                break

    
    def abandonSession(self,session):
        self.abandonSessionQueue.put(session)
        

    def _setProxySession(self,proxy):
        proxies = {"https":'https://'+proxy,
                        'http':'http://'+proxy}
        adapter_https = requests.adapters.HTTPAdapter(pool_connections=2,
                                                     pool_maxsize=2,
                                                     max_retries=0,
                                                     pool_block=False)
        session = requests.Session()
        session.mount('https://',adapter_https)
        session.proxies = proxies
        return session
    
    def _simpleTestConnection(self,proxyList):
        #first we test out our Internet connection state
        if testInternetConnection():
            for address in proxyList:
                if address.setTesting() == True:
                    common.logger(3,"ConnectManager._simpleTestConnection",\
                                      "Testing Session")
                    TCT =TestConnectionThread(address,self.availiableProxies)
                    TCT.start()
        else:
            pass #we should do something
        

    def shutDown(self):
        self.shutDownFlag = True

    def _closeSessions(self):
        for session in self.sessions:
            session.close()

def testInternetConnection(force = False):
    if not force and (lastTimeTestedInternetConnection == None or\
       time.time() - lastTimeTestedInternetConnection > 1):
        return True
    else:
        try:
            f = requests.head("http://www.bing.com")
            f.close()
            return True
        except(socket.timeout)or (socket.error) or IOError:
            return False
        except Exception as e:
            common.logger(1,"ConnectionService.testInternetConnection",e)
            return False

class TestConnectionThread(threading.Thread):
    def __init__(self, address, respondQueue):
        threading.Thread.__init__(self)
        self.address = address
        self.respondQueue = respondQueue
        self.fetch_server = globalVars.FETCH_SERVER
        self.HTTP_PROTOCOL = globalVars.HTTPS_ENABLE and "https" or "http"
        
    def testConnection(self,address):
        
        try:
            f = urllib.urlopen(self.fetch_server,
                               proxies = {self.HTTP_PROTOCOL:
                                          self.HTTP_PROTOCOL+"://"+address})
            return True
        except(httplib.HTTPException):
            return True
        except(socket.timeout)or (socket.error)or urllib.error.URLError or IOError:
            return False
        except Exception as e:
            common.logger(1,"ConnectionService.testConnection",e)
            return False
        
    def run(self):
        result = self.testConnection(self.address.getAddress())
        self.respondQueue.put((result,self.address))
        
class GFSIP():
    def __init__(self,address):
        self.address = address
        self.statusLock = thread.allocate_lock()
        self.status =   0#  not used, not tested
                    #   1   not used, testing
                    #   2   using
                    #   3   abandoned

    def _statusSetter(self, accept, newValue):
        result = False
        self.statusLock.acquire()
        if self.status in accept:
            self.status = newValue
            result = True
        self.statusLock.release()
        return result

    def setTesting(self):
        return self._statusSetter([0,],1)
    
    def setUsing(self):
        return self._statusSetter([1,],2)  
    
    def setAbandon(self):
        return self._statusSetter([1,2],3)

    def isTested(self):
        result = True
        self.statusLock.acquire()
        if self.status == 0:
            result = False
        self.statusLock.release()
        return result

    def getAddress(self):
        return self.address
    
CM = ConnectManager()
def getCM():
    return CM

if __name__ == "__main__":
    cm = getCM()
    cm.start()
    #cm.getSession()

